// ============================================================================
// 错误处理器
// ============================================================================

import { AppError, AppErrorType, ErrorEvent } from '../../shared/types'
import { generateUUID } from '../../shared/utils'

/**
 * 错误上下文信息
 */
export interface ErrorContext {
  [key: string]: any
}

/**
 * 错误处理选项
 */
export interface ErrorHandlingOptions {
  shouldExit?: boolean
  shouldNotify?: boolean
  shouldLog?: boolean
  context?: ErrorContext
}

/**
 * 错误处理器接口
 */
export interface IErrorHandler {
  handleError(error: Error | AppError, source?: string, options?: ErrorHandlingOptions): void
  createAppError(type: AppErrorType, message: string, details?: any): AppError
  isAppError(error: any): error is AppError
}

/**
 * 错误处理器实现
 */
export class ErrorHandler implements IErrorHandler {
  private errorListeners: Array<(error: AppError, source?: string) => void> = []

  /**
   * 处理错误
   */
  handleError(error: Error | AppError, source?: string, options: ErrorHandlingOptions = {}): void {
    const {
      shouldExit = false,
      shouldNotify = true,
      shouldLog = true,
      context = {}
    } = options

    // 转换为应用错误
    const appError = this.isAppError(error) ? error : this.convertToAppError(error)
    
    // 添加上下文信息
    if (Object.keys(context).length > 0) {
      appError.details = { ...appError.details, context }
    }

    // 记录错误日志
    if (shouldLog) {
      this.logError(appError, source)
    }

    // 通知错误监听器
    if (shouldNotify) {
      this.notifyErrorListeners(appError, source)
    }

    // 如果需要退出应用
    if (shouldExit) {
      this.exitApplication(appError)
    }
  }

  /**
   * 创建应用错误
   */
  createAppError(type: AppErrorType, message: string, details?: any): AppError {
    const error: AppError = {
      type,
      code: this.generateErrorCode(type),
      message,
      details,
      timestamp: new Date()
    }

    // 只有当 stack 存在时才添加
    const stack = new Error().stack
    if (stack) {
      error.stack = stack
    }

    return error
  }

  /**
   * 检查是否为应用错误
   */
  isAppError(error: any): error is AppError {
    return error && 
           typeof error === 'object' && 
           'type' in error && 
           'code' in error && 
           'message' in error && 
           'timestamp' in error
  }

  /**
   * 添加错误监听器
   */
  addErrorListener(listener: (error: AppError, source?: string) => void): void {
    this.errorListeners.push(listener)
  }

  /**
   * 移除错误监听器
   */
  removeErrorListener(listener: (error: AppError, source?: string) => void): void {
    const index = this.errorListeners.indexOf(listener)
    if (index > -1) {
      this.errorListeners.splice(index, 1)
    }
  }

  /**
   * 清除所有错误监听器
   */
  clearErrorListeners(): void {
    this.errorListeners = []
  }

  /**
   * 转换普通错误为应用错误
   */
  private convertToAppError(error: Error): AppError {
    let type: AppErrorType = 'UNKNOWN_ERROR'
    
    // 根据错误类型和消息推断错误类型
    if (error.message.includes('ENOTFOUND') || error.message.includes('ECONNREFUSED')) {
      type = 'NETWORK_ERROR'
    } else if (error.message.includes('ENOENT') || error.message.includes('EACCES')) {
      type = 'FILE_SYSTEM_ERROR'
    } else if (error.message.includes('SQLITE') || error.message.includes('database')) {
      type = 'DATABASE_ERROR'
    } else if (error.message.includes('validation') || error.message.includes('invalid')) {
      type = 'VALIDATION_ERROR'
    } else if (error.message.includes('auth') || error.message.includes('login')) {
      type = 'AUTH_ERROR'
    }

    const appError: AppError = {
      type,
      code: this.generateErrorCode(type),
      message: error.message,
      details: {
        originalError: error.name,
        stack: error.stack
      },
      timestamp: new Date()
    }

    // 只有当 stack 存在时才添加
    if (error.stack) {
      appError.stack = error.stack
    }

    return appError
  }

  /**
   * 生成错误代码
   */
  private generateErrorCode(type: AppErrorType): string {
    const timestamp = Date.now().toString(36)
    const random = Math.random().toString(36).substring(2, 7)
    return `${type}_${timestamp}_${random}`.toUpperCase()
  }

  /**
   * 记录错误日志
   */
  private logError(error: AppError, source?: string): void {
    const logMessage = [
      `[ERROR] ${error.type}: ${error.message}`,
      source ? `Source: ${source}` : '',
      `Code: ${error.code}`,
      `Timestamp: ${error.timestamp.toISOString()}`,
      error.details ? `Details: ${JSON.stringify(error.details, null, 2)}` : '',
      error.stack ? `Stack: ${error.stack}` : ''
    ].filter(Boolean).join('\n')

    console.error(logMessage)
  }

  /**
   * 通知错误监听器
   */
  private notifyErrorListeners(error: AppError, source?: string): void {
    for (const listener of this.errorListeners) {
      try {
        listener(error, source)
      } catch (listenerError) {
        console.error('Error in error listener:', listenerError)
      }
    }
  }

  /**
   * 退出应用程序
   */
  private exitApplication(error: AppError): void {
    console.error('Fatal error occurred, exiting application:', error)
    
    // 给一些时间让日志写入
    setTimeout(() => {
      process.exit(1)
    }, 1000)
  }
}

/**
 * 错误处理装饰器
 */
export function HandleErrors(options: ErrorHandlingOptions = {}) {
  return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value

    descriptor.value = async function (...args: any[]) {
      try {
        return await method.apply(this, args)
      } catch (error) {
        const errorHandler = new ErrorHandler()
        errorHandler.handleError(
          error as Error,
          `${target.constructor.name}.${propertyName}`,
          options
        )
        throw error
      }
    }

    return descriptor
  }
}

/**
 * 异步错误处理包装器
 */
export function wrapAsync<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  errorHandler: IErrorHandler,
  source?: string
): T {
  return (async (...args: any[]) => {
    try {
      return await fn(...args)
    } catch (error) {
      errorHandler.handleError(error as Error, source)
      throw error
    }
  }) as T
}

/**
 * 同步错误处理包装器
 */
export function wrapSync<T extends (...args: any[]) => any>(
  fn: T,
  errorHandler: IErrorHandler,
  source?: string
): T {
  return ((...args: any[]) => {
    try {
      return fn(...args)
    } catch (error) {
      errorHandler.handleError(error as Error, source)
      throw error
    }
  }) as T
}
